/******************************************************************************
 Copyright (c)2024 - 2025 Qualcomm Technologies International, Ltd.
 All Rights Reserved.
 Qualcomm Technologies International, Ltd. Confidential and Proprietary.

******************************************************************************/

#include "csr_bt_usr_config.h"
#include "csr_bt_config.h"

#ifdef INSTALL_CHANNEL_SOUNDING_SUPPORT
#include "gatt_ras_server_private.h"
#include "gatt_ras_server_debug.h"
#include "gatt_ras_server_access.h"
#include "gatt_ras_server_notify_indicate.h"
#include "gatt_ras_server_msg_handler.h"


static void rasServerSendConfigChangeIndication(GRASS_T  *const rasSrver,
    ConnectionIdType cid,
    bool configChangeComplete)
{
    /* Indicate the application all CCCD are written by client */
    MAKE_RAS_MESSAGE(GattRasServerConfigChangeInd);

    message->rasServiceHandle = rasSrver->srvcHndl;
    message->cid = cid;
    message->id = GATT_RAS_SERVER_CONFIG_CHANGE_IND;
    message->configChangeComplete = configChangeComplete;

    RasServerMessageSend(rasSrver->appTask, message);
}

void rasServerNotifyToApp(GRASS_T  *const rasSrver,
    ConnectionIdType cid,
    GattRasServerOperation operation,
    uint16 rangingCounter,
    uint8 startSegment,
    uint8 endSegment)
{
    MAKE_RAS_MESSAGE(GattRasServerRangingDataOperationInd);

    message->rasServiceHandle = rasSrver->srvcHndl;
    message->cid = cid;
    message->id = GATT_RAS_SERVER_RANGING_DATA_OPERATION_IND;
    message->rangingCounter = rangingCounter;
    message->operation = operation;
    message->startSegment = startSegment;
    message->endSegment = endSegment;

    RasServerMessageSend(rasSrver->appTask, message);
}

static bool rasServerAllClientConfigWritten(GRASS_T  *const rasSrver,
    ConnectionIdType cid)
{
    uint8 connectionIndex;

    for(connectionIndex = 0; connectionIndex < GATT_RAS_MAX_CONNECTIONS; connectionIndex++)
    {
        if(rasSrver->data.connectedClients[connectionIndex].cid == cid &&
            rasSrver->data.connectedClients[connectionIndex].clientCfg.realTimeDataClientCfg != GATT_RAS_SERVER_INVALID_CLIENT_CONFIG &&
            rasSrver->data.connectedClients[connectionIndex].clientCfg.onDemandDataClientCfg != GATT_RAS_SERVER_INVALID_CLIENT_CONFIG &&
            rasSrver->data.connectedClients[connectionIndex].clientCfg.controlPointClientCfg != GATT_RAS_SERVER_INVALID_CLIENT_CONFIG &&
            rasSrver->data.connectedClients[connectionIndex].clientCfg.dataReadyClientCfg != GATT_RAS_SERVER_INVALID_CLIENT_CONFIG &&
            rasSrver->data.connectedClients[connectionIndex].clientCfg.dataOverwrittenClientCfg != GATT_RAS_SERVER_INVALID_CLIENT_CONFIG)
        {
            return TRUE;
        }
    }

    return FALSE;
}

static void rasServerSetClientConfigWrite(GRASS_T  *const rasSrver,
    ConnectionIdType cid,
    bool clientConfigChanged)
{
    bool configChangeComplete = rasServerAllClientConfigWritten(rasSrver, cid);

    if (clientConfigChanged)
    {
        /* Inform above layer about CCCD change*/
        rasServerSendConfigChangeIndication(rasSrver,
                                         cid,
                                         configChangeComplete);
    }
}


static bool rasServerClientConfigChanged(uint16 clientCfg, uint8 newClientCfg)
{
    /* Check if the client config has changed, to notify above layer */
    return(((uint8)clientCfg) != newClientCfg);
}

/***************************************************************************/
static status_t rasServerCheckIfRealTimeAndOnDemandBothEnabled(
                            GRASS_T *const rasSrver,
                            ConnectionIdType cid,
                            uint16 handle,
                            uint8 *ccc)
{
    uint8 index_client = rasServerGetCidIndex(rasSrver, cid);
    status_t status = CSR_BT_GATT_ACCESS_RES_SUCCESS;

    if(index_client != GATT_RAS_SERVER_INVALID_CID_INDEX)
    {
        if (handle == HANDLE_REALTIME_RANGING_DATA_CLIENT_CONFIG)
        {
            /* We need to check if OnDemand Ranging Data is enabled already or not */
            if(ccc[0] > 0 && 
                rasSrver->data.connectedClients[index_client].clientCfg.onDemandDataClientCfg > 0)
            {
                status = CSR_BT_GATT_ACCESS_RES_CLIENT_CONFIG_IMPROPERLY_CONF;
            }
        }
        else
        {
            /* We need to check if RealTime Ranging Data is enabled already or not */
            if(ccc[0] > 0 && 
                rasSrver->data.connectedClients[index_client].clientCfg.realTimeDataClientCfg > 0)
            {
                status = CSR_BT_GATT_ACCESS_RES_CLIENT_CONFIG_IMPROPERLY_CONF;
            }
        }
    }

    return status;
}

/***************************************************************************/
static status_t rasServerSetCCC(GRASS_T *const rasSrver,
                                ConnectionIdType cid,
                                uint16 handle,
                                uint8 *ccc)
{
    uint8 index_client = rasServerGetCidIndex(rasSrver, cid);
    bool clientConfigChanged = FALSE;

    if(index_client != GATT_RAS_SERVER_INVALID_CID_INDEX)
    {
        if (handle == HANDLE_REALTIME_RANGING_DATA_CLIENT_CONFIG)
        {
            /* Check if the client config has changed, to notify above layer */
            clientConfigChanged = rasServerClientConfigChanged(
                  rasSrver->data.connectedClients[index_client].clientCfg.realTimeDataClientCfg,
                                  ccc[0]);

            rasSrver->data.connectedClients[index_client].clientCfg.realTimeDataClientCfg = ccc[0];
            GATT_RAS_SERVER_INFO("RAS: rasServerSetCCC: cid :%x  cfg =%x handle: %x \n", cid, rasSrver->data.connectedClients[index_client].clientCfg.realTimeDataClientCfg, handle );

            if (ccc[0] > 0)
            {
                rasSrver->data.connectedClients[index_client].rangingDataRequested = TRUE;
            }
            else
            {
                rasSrver->data.connectedClients[index_client].rangingDataRequested = FALSE;
            }
        }
        else if (handle == HANDLE_ONDEMAND_RANGING_DATA_CLIENT_CONFIG)
        {
            /* Check if the client config has changed, to notify above layer */
            clientConfigChanged = rasServerClientConfigChanged(
                  rasSrver->data.connectedClients[index_client].clientCfg.onDemandDataClientCfg,
                                  ccc[0]);

            rasSrver->data.connectedClients[index_client].clientCfg.onDemandDataClientCfg = ccc[0];
            GATT_RAS_SERVER_INFO("RAS: rasServerSetCCC: cid :%x  cfg =%x handle: %x \n", cid, rasSrver->data.connectedClients[index_client].clientCfg.onDemandDataClientCfg , handle );
        }
        else if (handle == HANDLE_RAS_CONTROL_POINT_CLIENT_CONFIG)
        {
            clientConfigChanged = rasServerClientConfigChanged(
                  rasSrver->data.connectedClients[index_client].clientCfg.controlPointClientCfg,
                                  ccc[0]);

            rasSrver->data.connectedClients[index_client].clientCfg.controlPointClientCfg = ccc[0];
            GATT_RAS_SERVER_INFO("RAS: rasServerSetCCC: cid :%x  cfg =%x handle: %x \n", cid, rasSrver->data.connectedClients[index_client].clientCfg.controlPointClientCfg , handle);
        }
        else if (handle == HANDLE_RANGING_DATA_READY_CLIENT_CONFIG)
        {
            clientConfigChanged = rasServerClientConfigChanged(
                  rasSrver->data.connectedClients[index_client].clientCfg.dataReadyClientCfg,
                                  ccc[0]);

            rasSrver->data.connectedClients[index_client].clientCfg.dataReadyClientCfg = ccc[0];
            GATT_RAS_SERVER_INFO("RAS: rasServerSetCCC: cid :%x  cfg =%x handle: %x \n", cid, rasSrver->data.connectedClients[index_client].clientCfg.dataReadyClientCfg , handle);
        }
        else if (handle == HANDLE_RANGING_DATA_OVERWRITTEN_CLIENT_CONFIG)
        {
            clientConfigChanged = rasServerClientConfigChanged(
                  rasSrver->data.connectedClients[index_client].clientCfg.dataOverwrittenClientCfg,
                                  ccc[0]);

            rasSrver->data.connectedClients[index_client].clientCfg.dataOverwrittenClientCfg = ccc[0];
            GATT_RAS_SERVER_INFO("RAS: rasServerSetCCC: cid :%x  cfg =%x handle: %x \n", cid, rasSrver->data.connectedClients[index_client].clientCfg.dataOverwrittenClientCfg, handle);
        }
        else
        {
            /* Invalid handle */
            GATT_RAS_SERVER_ERROR("Invalid handle!\n");
            return CSR_BT_GATT_ACCESS_RES_INVALID_HANDLE;
        }

        /* Inform application for client write operation */
        rasServerSetClientConfigWrite(rasSrver, cid, clientConfigChanged);
    }
    else
    {
        /* Invalid cid */
        GATT_RAS_SERVER_ERROR("Invalid cid!\n");
        return CSR_BT_GATT_ACCESS_RES_INVALID_PDU;
    }

    return CSR_BT_GATT_ACCESS_RES_SUCCESS;
}


/******************************************************************************/
uint8 rasServerGetCidIndex(const GRASS_T *rasSrver, ConnectionIdType cid)
{
    uint8 index = GATT_RAS_SERVER_INVALID_CID_INDEX;
    uint8 currentIndex;

    for (currentIndex = 0; currentIndex < GATT_RAS_MAX_CONNECTIONS; currentIndex++)
    {
        if(rasSrver->data.connectedClients[currentIndex].cid == cid)
        {
            index = currentIndex;
            break;
        }
    }

    return index;
}

/***************************************************************************
NAME
    sendRasServerAccessRsp

DESCRIPTION
    Send an access response to the GATT Manager library.
*/
void sendRasServerAccessRsp(CsrBtGattId task,
                                  ConnectionIdType cid,
                                  uint16 handle,
                                  uint16 result,
                                  uint16 size_value,
                                  uint8 *const value)
{
    uint8* data;

    data = (uint8*)CsrPmemZalloc(size_value);
    CsrMemCpy(data, value, size_value);

    CsrBtGattDbReadAccessResSend(
                                task,
                                cid,
                                handle,
                                result,
                                size_value,
                                data);
}

/***************************************************************************
NAME
    sendRasServerAccessErrorRsp

DESCRIPTION
    Send an error access response to the GATT  library.
*/
static void sendRasServerAccessErrorRsp(CsrBtGattId task,
                            const GATT_MANAGER_SERVER_ACCESS_IND_T *access_ind,
                            uint16 error)
{
    sendRasServerAccessRsp(task,
                           access_ind->cid,
                           access_ind->handle,
                           error,
                           0,
                           NULL);
}

/***************************************************************************
NAME
    sendRasServerWriteAccessRsp

DESCRIPTION
    Send an access response to the GATT Manager library.
*/
static void sendRasServerWriteAccessRsp(CsrBtGattId task,
                                        ConnectionIdType cid,
                                        uint16 handle,
                                        uint16 result,
                                        uint16 size_value,
                                        uint8 *const value)
{
    CSR_UNUSED(size_value);
    CSR_UNUSED(value);

    CsrBtGattDbWriteAccessResSend(task,
                                  cid,
                                  handle,
                                  (CsrBtGattDbAccessRspCode)result);
}

/***************************************************************************
NAME
    sendRasServerWriteAccessErrorRsp

DESCRIPTION
    Send an error access response to the GATT Manager library.
*/

static void sendRasServerWriteAccessErrorRsp(CsrBtGattId task,
                            const GATT_MANAGER_SERVER_ACCESS_IND_T *accessInd,
                            uint16 error)
{
    sendRasServerWriteAccessRsp(task,
                                accessInd->cid,
                                accessInd->handle,
                                error,
                                0,
                                NULL);
}


/***************************************************************************
NAME
    rasServerServiceAccess

DESCRIPTION
    Deals with access of the HANDLE_RANGING_SERVICE handle.
*/
static void rasServerServiceAccess(CsrBtGattId task, const GATT_MANAGER_SERVER_ACCESS_IND_T *accessInd)
{
    if (accessInd->flags & ATT_ACCESS_READ)
    {
        sendRasServerAccessRsp(task,
                               accessInd->cid,
                               HANDLE_RANGING_SERVICE,
                               CSR_BT_GATT_ACCESS_RES_SUCCESS,
                               0,
                               NULL);
    }
    else if (accessInd->flags & ATT_ACCESS_WRITE)
    {
        /* Write of RAS not allowed. */
        sendRasServerWriteAccessErrorRsp(task, accessInd, CSR_BT_GATT_ACCESS_RES_WRITE_NOT_PERMITTED);
    }
    else
    {
        /* Reject access requests that aren't read/write, which shouldn't happen. */
        sendRasServerAccessErrorRsp(task, accessInd, CSR_BT_GATT_ACCESS_RES_REQUEST_NOT_SUPPORTED);
    }
}

/***************************************************************************
NAME
    rasServerRasFeaturesAccess

DESCRIPTION
    Deals with access of the HANDLE_RAS_FEATURE handle.
*/
static void rasServerRasFeaturesAccess(
    const GRASS_T *rasSrver,
    const GATT_MANAGER_SERVER_ACCESS_IND_T *accessInd)
{
    uint8 rasFeaturesResp[GATT_RAS_FEATURES_VALUE_SIZE];

    if (accessInd->flags & ATT_ACCESS_READ)
    {
        GATT_RAS_SERVER_INFO("RAS Features :%x", rasSrver->data.rasFeaturesMask);

        rasFeaturesResp[0] = (uint8)rasSrver->data.rasFeaturesMask & 0xFF;
        rasFeaturesResp[1] = (uint8)(rasSrver->data.rasFeaturesMask >> 8) & 0xFF;
        rasFeaturesResp[2] = (uint8)(rasSrver->data.rasFeaturesMask >> 16) & 0xFF;
        rasFeaturesResp[3] = (uint8)(rasSrver->data.rasFeaturesMask >> 24) & 0xFF;

        sendRasServerAccessRsp(
                rasSrver->gattId,
                accessInd->cid,
                accessInd->handle,
                CSR_BT_GATT_ACCESS_RES_SUCCESS,
                GATT_RAS_FEATURES_VALUE_SIZE,
                rasFeaturesResp
                );
    }
    else
    {
        sendRasServerAccessErrorRsp(
                    rasSrver->gattId,
                    accessInd,
                    CSR_BT_GATT_ACCESS_RES_REQUEST_NOT_SUPPORTED
                    );
    }
}

/***************************************************************************
NAME
    rasServerRangingDataReadyAccess

DESCRIPTION
    Deals with access of the HANDLE_RANGING_DATA_READY handle.
*/
static void rasServerRangingDataReadyAccess(
    const GRASS_T *rasSrver,
    const GATT_MANAGER_SERVER_ACCESS_IND_T *accessInd)
{
    uint8 rangingDataReadyValueResp[GATT_RAS_SERVER_RANGING_DATA_VALUE_SIZE];
    uint8 index_client = rasServerGetCidIndex(rasSrver, accessInd->cid);

    if (accessInd->flags & ATT_ACCESS_READ)
    {
        GATT_RAS_SERVER_INFO("RangingDataReady handle value :%x", rasSrver->data.connectedClients[index_client].curRangingCounter);

        rangingDataReadyValueResp[0] = (uint8)rasSrver->data.connectedClients[index_client].curRangingCounter & 0xFF;
        rangingDataReadyValueResp[1] = (uint8)(rasSrver->data.connectedClients[index_client].curRangingCounter >> 8) & 0xFF;

        sendRasServerAccessRsp(
                rasSrver->gattId,
                accessInd->cid,
                accessInd->handle,
                CSR_BT_GATT_ACCESS_RES_SUCCESS,
                GATT_RAS_SERVER_RANGING_DATA_VALUE_SIZE,
                rangingDataReadyValueResp
                );
    }
    else
    {
        sendRasServerAccessErrorRsp(
                rasSrver->gattId,
                accessInd,
                CSR_BT_GATT_ACCESS_RES_REQUEST_NOT_SUPPORTED
                );
    }
}

/***************************************************************************
NAME
    rasServerRangingDataOverwrittenAccess

DESCRIPTION
    Deals with access of the HANDLE_RANGING_DATA_OVERWRITTEN handle.
*/
static void rasServerRangingDataOverwrittenAccess(
    const GRASS_T *rasSrver,
    const GATT_MANAGER_SERVER_ACCESS_IND_T *accessInd)
{
    uint8 rangingDataOverwrittenValueResp[GATT_RAS_SERVER_RANGING_DATA_VALUE_SIZE];
    uint8 index_client = rasServerGetCidIndex(rasSrver, accessInd->cid);

    if (accessInd->flags & ATT_ACCESS_READ)
    {
        GATT_RAS_SERVER_INFO("RangingDataOverwritten handle value :%x", rasSrver->data.connectedClients[index_client].lastRangingCounterOverwritten);

        rangingDataOverwrittenValueResp[0] = (uint8)rasSrver->data.connectedClients[index_client].lastRangingCounterOverwritten & 0xFF;
        rangingDataOverwrittenValueResp[1] = (uint8)(rasSrver->data.connectedClients[index_client].lastRangingCounterOverwritten >> 8) & 0xFF;

        sendRasServerAccessRsp(
                rasSrver->gattId,
                accessInd->cid,
                accessInd->handle,
                CSR_BT_GATT_ACCESS_RES_SUCCESS,
                GATT_RAS_SERVER_RANGING_DATA_VALUE_SIZE,
                rangingDataOverwrittenValueResp
                );
    }
    else
    {
        sendRasServerAccessErrorRsp(
                rasSrver->gattId,
                accessInd,
                CSR_BT_GATT_ACCESS_RES_REQUEST_NOT_SUPPORTED
                );
    }
}


static uint8 getLastSegmentRollingCounter(GRASS_T *rasSrver,uint8 index_client)
{
    uint8 rollingCounter = 0;
    ras_ranging_data_list *list = rasSrver->data.connectedClients[index_client].rangingDataList;

    while(list != NULL)
    {
        if ((list->data[0] & LAST_SEGMENT_TRUE) == LAST_SEGMENT_TRUE)
        {
           rollingCounter = (list->data[0] >> 2);
           break;
        }
        list = list->next;
    }

    GATT_RAS_SERVER_INFO("getLastSegmentRollingCounter: %x ", rollingCounter);

    return rollingCounter;
}

static uint8* getSegmentDatabyRollingCounter(GRASS_T *rasSrver,uint8 index_client,uint8* size, uint8 rollingCounter)
{
    uint8 *data = NULL;
    ras_ranging_data_list *list = rasSrver->data.connectedClients[index_client].rangingDataList;

    while(list != NULL)
    {
        if (list->rollingCounter == rollingCounter)
        {
           data = list->data;
           *size = (uint8) list->dataLen;
           break;
        }
        list = list->next;
    }

    GATT_RAS_SERVER_INFO("Segment Size: %x ", *size);

    return data;
}

static void rasServerGetRangingDataInd(
    GRASS_T *rasSrver,
    const GATT_MANAGER_SERVER_ACCESS_IND_T *accessInd)
{
    uint8 index_client = rasServerGetCidIndex(rasSrver, accessInd->cid);
    uint16 rangingCounter;

    if(index_client == GATT_RAS_SERVER_INVALID_CID_INDEX)
    {
        /* Invalid cid */
        GATT_RAS_SERVER_ERROR("Invalid cid!\n");
        return;
    }

    /* Validate if the operation has valid size */
    if (accessInd->size_value != GATT_RAS_CP_RANGING_DATA_GET_ACK_SIZE)
    {
        rasServerRasCpResponseCode(rasSrver,
                                     accessInd->cid,
                                     GATT_RAS_RESPONSE_CODE_INVALID_PARAMETER);
        return;
    }

    /* Get the Ranging Counter and see if we have got a valid ranging counter from remote */
    rangingCounter = (uint16)((accessInd->value[2] << 8) | accessInd->value[1]);

    if (rangingCounter != rasSrver->data.connectedClients[index_client].curRangingCounter)
    {
        rasServerRasCpResponseCode(rasSrver,
                                     accessInd->cid,
                                     GATT_RAS_RESPONSE_CODE_NO_RECORD_FOUND);

        return;
    }

    if (rasSrver->data.connectedClients[index_client].rangingDataRequested == TRUE &&
        rasSrver->data.connectedClients[index_client].allSegmentsSent == FALSE)
    {
        rasServerRasCpResponseCode(rasSrver,
                                   accessInd->cid,
                                   GATT_RAS_RESPONSE_CODE_SERVER_BUSY);
        return;
    }

    /* Notify to application about the Get Ranging Data indication */
    rasServerNotifyToApp(rasSrver,
                         accessInd->cid,
                         GATT_RAS_SERVER_OP_GET_RANGING_DATA,
                         rangingCounter,
                         0,
                         0);

    rasSrver->data.connectedClients[index_client].rangingDataRequested = TRUE;

    /* Trigger sending ranging data, may be it is already ready to be sent */
    rasServerSendRangingData(rasSrver, accessInd->cid, rangingCounter, HANDLE_ONDEMAND_RANGING_DATA);
}

static void rasServerAckRangingDataInd(
    GRASS_T *rasSrver,
    const GATT_MANAGER_SERVER_ACCESS_IND_T *accessInd)
{
    uint8 index_client = rasServerGetCidIndex(rasSrver, accessInd->cid);
    uint16 rangingCounter;
    gattRasServerResponseCode respondCodeValue;

    if(index_client == GATT_RAS_SERVER_INVALID_CID_INDEX)
    {
        /* Invalid cid */
        GATT_RAS_SERVER_ERROR("Invalid cid!\n");
        return;
    }

    /* Validate if the operation has valid size */
    if (accessInd->size_value != GATT_RAS_CP_RANGING_DATA_GET_ACK_SIZE)
    {
        rasServerRasCpResponseCode(rasSrver,
                                    accessInd->cid,
                                    GATT_RAS_RESPONSE_CODE_INVALID_PARAMETER);
        return;
    }

    /* Get the Ranging Counter and store it */
    rangingCounter = (uint16)((accessInd->value[2] << 8) | accessInd->value[1]);

    /* This should match with the current Ranging Counter stored 
    * assuming that we support only 1 CS procedure now.
    * May need to re-visit if RRSP can support multiple CS procedure.
    */
    if (rangingCounter != rasSrver->data.connectedClients[index_client].curRangingCounter)
    {
        respondCodeValue = GATT_RAS_RESPONSE_CODE_NO_RECORD_FOUND;
    }
    else if (rasSrver->data.connectedClients[index_client].procedureActive)
    {
        respondCodeValue = GATT_RAS_RESPONSE_CODE_SERVER_BUSY;
    }
    else
    {
        respondCodeValue = GATT_RAS_RESPONSE_CODE_SUCCESS;

        /* Notify to application about the ack  TBD */
        rasServerNotifyToApp(rasSrver,
                             accessInd->cid,
                             GATT_RAS_SERVER_OP_ACK_RANGING_DATA,
                             rangingCounter,
                             0,
                             0);

        /* Free the list */
        rasServerFreeRangingDataList(rasSrver, index_client);

        rasSrver->data.connectedClients[index_client].rangingDataRequested = FALSE;

        /* Reset number of segments */
        rasSrver->data.connectedClients[index_client].numOfSegments =0;
    }

    /* Indicate the client about the operation */
    rasServerRasCpResponseCode(rasSrver,
                               accessInd->cid,
                               respondCodeValue);
}



static void rasServerRetreiveLostRangingDataSegmentInd(
    GRASS_T *rasSrver,
    const GATT_MANAGER_SERVER_ACCESS_IND_T *accessInd)
{
    uint8 index_client = rasServerGetCidIndex(rasSrver, accessInd->cid);
    uint16 rangingCounter;
    uint8 startSegment, startSegmentCounter;
    uint8 endSegment, endSegmentCounter;
    uint8 *data;
    uint8 index, size;
    bool segmentsToSend = FALSE;

    if(index_client == GATT_RAS_SERVER_INVALID_CID_INDEX)
    {
        /* Invalid cid */
        GATT_RAS_SERVER_ERROR("Invalid cid!\n");
        return;
    }

    /* Validate if the operation has valid size */
    if (accessInd->size_value != GATT_RAS_CP_RLRDS_SIZE)
    {
        rasServerRasCpResponseCode(rasSrver,
                                   accessInd->cid,
                                   GATT_RAS_RESPONSE_CODE_INVALID_PARAMETER);
        return;
    }

    /* Get the Ranging Counter and store it */
    rangingCounter = (uint16)((accessInd->value[2] << 8) | accessInd->value[1]);

    /* This should match with the current Ranging Counter stored 
    * assuming that we support only 1 CS procedure now.
    * May need to re-visit if RRSP can support multiple CS procedure.
    */
    startSegmentCounter = accessInd->value[3];
    endSegmentCounter = accessInd->value[4];

    if(rangingCounter != rasSrver->data.connectedClients[index_client].curRangingCounter)
    {
        rasServerRasCpResponseCode(rasSrver,
                                    accessInd->cid,
                                    GATT_RAS_RESPONSE_CODE_NO_RECORD_FOUND);
                                    return;
    }

    /* Remote should not request for lost segments before even requesting ranging data */
    if (!rasSrver->data.connectedClients[index_client].rangingDataRequested)
    {
        rasServerRasCpResponseCode(rasSrver,
                                   accessInd->cid,
                                   GATT_RAS_RESPONSE_CODE_INVALID_PARAMETER);
                                   return;
    }

    /* Remote should not request ranging data again while sending notification */
    if (!rasSrver->data.connectedClients[index_client].allSegmentsSent)
    {
        rasServerRasCpResponseCode(rasSrver,
                                   accessInd->cid,
                                   GATT_RAS_RESPONSE_CODE_SERVER_BUSY);
                                   return;
    }

    else
    {
       startSegment = startSegmentCounter + 1;

       if (endSegmentCounter == END_SEGMENT_MAX)
       {
           /* remote does not know about the last segment counter, so
            * we need to get this value for the last segment counter
            */
            endSegmentCounter = getLastSegmentRollingCounter(rasSrver, index_client);
       }

       endSegment = endSegmentCounter + 1;
       if(startSegment < endSegment && endSegment > rasSrver->data.connectedClients[index_client].numOfSegments)
       {
           rasServerRasCpResponseCode(rasSrver,
                                       accessInd->cid,
                                       GATT_RAS_RESPONSE_CODE_NO_RECORD_FOUND);
       }
       else if(startSegment > endSegment || startSegment > rasSrver->data.connectedClients[index_client].numOfSegments)
       {
           rasServerRasCpResponseCode(rasSrver,
                                       accessInd->cid,
                                       GATT_RAS_RESPONSE_CODE_INVALID_PARAMETER);
       }
       else
       {
           segmentsToSend = TRUE;
       }
    }

    if (segmentsToSend)
    {

        /* Send the asked segments */
        for(index = startSegmentCounter; index <= endSegmentCounter; index++)
        {
            data = getSegmentDatabyRollingCounter(rasSrver,index_client, &size, index);

            rasServerSendRasData(
                        rasSrver,
                        accessInd->cid,
                        HANDLE_ONDEMAND_RANGING_DATA,
                        size,
                        data);
         }

         /* Notify the Application */
         rasServerNotifyToApp(rasSrver,
                              accessInd->cid,
                              GATT_RAS_SERVER_OP_COMPLETE_LOST_RANGING_DATA,
                              rasSrver->data.connectedClients[index_client].curRangingCounter,
                              startSegmentCounter,
                              endSegmentCounter);
    }
}

static void rasServerFilterRangingDataInd(
    GRASS_T *rasSrver,
    const GATT_MANAGER_SERVER_ACCESS_IND_T *accessInd)
{
    uint8 index_client = rasServerGetCidIndex(rasSrver, accessInd->cid);
    uint8 mode;
    uint16 filterMask;
    gattRasServerResponseCode respondCodeValue;

    if(index_client == GATT_RAS_SERVER_INVALID_CID_INDEX)
    {
        /* Invalid cid */
        GATT_RAS_SERVER_ERROR("Invalid cid!\n");
        return;
    }

    mode = (accessInd->value[1] & 0x03);
    filterMask = (uint16)((accessInd->value[2] << 8) | ((accessInd->value[1] & 0xFC)));
    filterMask = (filterMask >> 2);

    GATT_RAS_SERVER_INFO("Mode : %x, FilterMask for mode =%x", mode, filterMask);

    /* TBD sanity checking for filterMask for different modes */
    if (accessInd->size_value != GATT_RAS_CP_FILTER_RANGING_DATA_SIZE)
    {
        respondCodeValue = GATT_RAS_RESPONSE_CODE_INVALID_PARAMETER;
    }
    else if (rasSrver->data.connectedClients[index_client].clientCfg.onDemandDataClientCfg == GATT_RAS_SERVER_CCC_NOTIFY ||
        rasSrver->data.connectedClients[index_client].clientCfg.onDemandDataClientCfg == GATT_RAS_SERVER_CCC_INDICATE ||
        rasSrver->data.connectedClients[index_client].clientCfg.realTimeDataClientCfg == GATT_RAS_SERVER_CCC_NOTIFY ||
        rasSrver->data.connectedClients[index_client].clientCfg.realTimeDataClientCfg == GATT_RAS_SERVER_CCC_INDICATE)
    {
        respondCodeValue = GATT_RAS_RESPONSE_CODE_INVALID_PARAMETER;
    }
    else
    {
        respondCodeValue = GATT_RAS_RESPONSE_CODE_SUCCESS;
        rasSrver->data.connectedClients[index_client].filterMask[mode] = filterMask;
    }

    /* Indicate the client about the operation */
    rasServerRasCpResponseCode(rasSrver,
                               accessInd->cid,
                               respondCodeValue);
}

static void rasServerAbortOperationInd(
    GRASS_T *rasSrver,
    const GATT_MANAGER_SERVER_ACCESS_IND_T *accessInd)
{
    uint8 index_client = rasServerGetCidIndex(rasSrver, accessInd->cid);

    if(index_client == GATT_RAS_SERVER_INVALID_CID_INDEX)
    {
        /* Invalid cid */
        GATT_RAS_SERVER_ERROR("Invalid cid!\n");
        return;
    }

    /* Validate if the operation has valid size */
    if (accessInd->size_value != GATT_RAS_CP_ABORT_REQ_SIZE)
    {
        rasServerRasCpResponseCode(rasSrver,
                                    accessInd->cid,
                                    GATT_RAS_RESPONSE_CODE_INVALID_PARAMETER);
        return;
    }

    rasSrver->data.connectedClients[index_client].rangingDataRequested = FALSE;

    /* We can get a request to transmit this ranging counter procedure again
     * so make list->transmitted for this to FALSE
     */
    rasServerSetAllSegmentToTransmit(rasSrver, index_client);

    rasServerNotifyToApp(rasSrver,
                         accessInd->cid,
                         GATT_RAS_SERVER_OP_ABORT_OPERATION,
                         rasSrver->data.connectedClients[index_client].curRangingCounter,
                         0,
                         0);

    /* Indicate the client about the operation */
    rasServerRasCpResponseCode(rasSrver,
                                accessInd->cid,
                                GATT_RAS_RESPONSE_CODE_SUCCESS);
}


/***************************************************************************
NAME
    rasServerControlPointAccess

DESCRIPTION
    Deals with access of the HANDLE_RAS_CONTROL_POINT handle.
*/
static void rasServerControlPointAccess(
    GRASS_T *rasSrver,
    const GATT_MANAGER_SERVER_ACCESS_IND_T *accessInd)
{
    GATT_RAS_SERVER_INFO("Size: 0x%x flags =%x",accessInd->size_value, accessInd->flags);

    if (accessInd->flags & ATT_ACCESS_WRITE)
    {
        uint8 opcode;

        /* Send response to the client for write, indication will follow
         * later based on opcode
         */
        sendRasServerWriteAccessRsp(rasSrver->gattId,
                                    accessInd->cid,
                                    accessInd->handle,
                                    CSR_BT_GATT_ACCESS_RES_SUCCESS,
                                    0,
                                    NULL);
        opcode = accessInd->value[0];
        GATT_RAS_SERVER_INFO("Control Point Access Opcode 0x%x, Size: 0x%x flags =%x",opcode, accessInd->size_value, accessInd->flags);

        switch(opcode)
        {
            case GATT_RAS_SERVER_GET_RANGING_DATA:
            {
                GATT_RAS_SERVER_INFO("<< 0x%x 0x%x 0x%x\n", accessInd->value[0], accessInd->value[1], accessInd->value[2]);
                rasServerGetRangingDataInd(rasSrver, accessInd);
                break;
            }

            case GATT_RAS_SERVER_ACK_RANGING_DATA:
            {
                GATT_RAS_SERVER_INFO("<< 0x%x 0x%x 0x%x\n", accessInd->value[0], accessInd->value[1], accessInd->value[2]);
                rasServerAckRangingDataInd(rasSrver, accessInd);
                break;
            }

            case GATT_RAS_SERVER_RETRIEVE_LOST_RANGING_DATA_SEGMENTS:
            {
                GATT_RAS_SERVER_INFO("<< 0x%x 0x%x 0x%x 0x%x 0x%x\n", accessInd->value[0], accessInd->value[1], accessInd->value[2],
                    accessInd->value[3], accessInd->value[4]);
                rasServerRetreiveLostRangingDataSegmentInd(rasSrver, accessInd);
                break;
            }

            case GATT_RAS_SERVER_ABORT_OPERATION:
            {
                GATT_RAS_SERVER_INFO("<< 0x%x \n", accessInd->value[0]);
                rasServerAbortOperationInd(rasSrver, accessInd);
                break;
            }

            case GATT_RAS_SERVER_FILTER_RANGING_DATA:
            {
                GATT_RAS_SERVER_INFO("<< 0x%x 0x%x 0x%x\n", accessInd->value[0], accessInd->value[1], accessInd->value[2]);
                rasServerFilterRangingDataInd(rasSrver, accessInd);
                break;
            }

            default:
            {
                /* We don't recognise this opcode */
                /* Send the RAS CP Indication with response code = 2 and
                 * response value as 0x02 (Op Code not supported)
                 */
                GATT_RAS_SERVER_INFO("Indicate OpResponse: 0x%x",GATT_RAS_RESPONSE_CODE_UNSUPPORTED_OPCODE);
                rasServerRasCpResponseCode(rasSrver,
                                            accessInd->cid,
                                            GATT_RAS_RESPONSE_CODE_UNSUPPORTED_OPCODE);
            }
            break;
        }
    }
    else
    {
        sendRasServerAccessErrorRsp(
                rasSrver->gattId,
                accessInd,
                CSR_BT_GATT_ACCESS_RES_REQUEST_NOT_SUPPORTED
                );
    }
}



/***************************************************************************/
static void rasHandleReadClientConfigAccess(
        CsrBtGattId task,
        ConnectionIdType cid,
        uint16 handle,
        const uint16 client_config
        )
{
    uint8 config_data[GATT_RAS_SERVER_CCC_VALUE_SIZE];

    if (task == CSR_BT_GATT_INVALID_GATT_ID)
    {
        GATT_RAS_SERVER_PANIC(
                    "RAS: Null instance!\n"
                    );
    }
    else if (cid == CSR_BT_CONN_ID_INVALID)
    {
        GATT_RAS_SERVER_PANIC(
                    "RAS: Null instance!\n"
                    );
    }

    /* Default value of clientConfig is set as 0xFFFF. If client has not written
       any CCCD then we need to replace 0xFFFF with 0x0 (Disable) while
       responding. Default value is changed from 0 to 0xFFFF because of
       CCCD values getting lost if the device panics without these values are
       passed to application.
     */
    if(client_config != GATT_RAS_SERVER_INVALID_CLIENT_CONFIG)
    {
        config_data[0] = (uint8)(client_config & 0xFF);
        config_data[1] = (uint8)(client_config >> 8);
    }
    else
    {
        config_data[0] = 0;
        config_data[1] = 0;
    }

    sendRasServerAccessRsp(
            task,
            cid,
            handle,
            CSR_BT_GATT_ACCESS_RES_SUCCESS,
            GATT_RAS_SERVER_CCC_VALUE_SIZE,
            config_data
            );
}


/***************************************************************************/
static void rasHandleWriteClientConfigAccess(
        GRASS_T *rasSrver,
        const GATT_MANAGER_SERVER_ACCESS_IND_T *access_ind
        )
{
    if (access_ind->size_value != GATT_RAS_SERVER_CCC_VALUE_SIZE)
    {
        sendRasServerWriteAccessErrorRsp(
                rasSrver->gattId,
                access_ind,
                CSR_BT_GATT_ACCESS_RES_INVALID_LENGTH
                );
    }
    else if ( (access_ind->value[0] == GATT_RAS_SERVER_CCC_NOTIFY) &&
              (access_ind->handle == HANDLE_RAS_CONTROL_POINT_CLIENT_CONFIG ||
               access_ind->handle == HANDLE_RANGING_DATA_READY_CLIENT_CONFIG ||
               access_ind->handle == HANDLE_RANGING_DATA_OVERWRITTEN_CLIENT_CONFIG))
    {
        sendRasServerWriteAccessErrorRsp(
                rasSrver->gattId,
                access_ind,
                CSR_BT_GATT_ACCESS_RES_WRITE_REQUEST_REJECTED
                );
    }
    else if ( (access_ind->value[0] == GATT_RAS_SERVER_CCC_NOTIFY || access_ind->value[0] == 0 ) ||
        (access_ind->value[0] == GATT_RAS_SERVER_CCC_INDICATE || access_ind->value[0] == 0 ) ||
        (access_ind->value[0] == (GATT_RAS_SERVER_CCC_INDICATE | GATT_RAS_SERVER_CCC_NOTIFY)
         || access_ind->value[0] == 0 ))
    {
        /* Valid value of CCC */

        /* Check if client is trying to enable Ranging Data Char and OnDemand Ranging Data char both */
        status_t status = CSR_BT_GATT_ACCESS_RES_SUCCESS;

        if (access_ind->handle == HANDLE_REALTIME_RANGING_DATA_CLIENT_CONFIG ||
            access_ind->handle == HANDLE_ONDEMAND_RANGING_DATA_CLIENT_CONFIG)
        {
            status = rasServerCheckIfRealTimeAndOnDemandBothEnabled(
                           rasSrver,
                           (connection_id_t) access_ind->cid,
                           access_ind->handle,
                           access_ind->value
                           );
        }

        if ( status == CSR_BT_GATT_ACCESS_RES_SUCCESS)
        {
            /* Save the new ccc in the library */
            status = rasServerSetCCC(
                                     rasSrver,
                                     (connection_id_t) access_ind->cid,
                                     access_ind->handle,
                                     access_ind->value);
        }

        /* Send response to the client */
        sendRasServerWriteAccessRsp(
             rasSrver->gattId,
             access_ind->cid,
             access_ind->handle,
             status,
             0,
             NULL
             );
    }
    else
    {
        /* Send response to the client but the value is ignored*/
        sendRasServerWriteAccessRsp(
             rasSrver->gattId,
             access_ind->cid,
             access_ind->handle,
             CSR_BT_GATT_ACCESS_RES_SUCCESS,
             0,
             NULL
             );
    }
}

static void rasHandleClientConfigAccess(GRASS_T *const rasSrver,
              const GATT_MANAGER_SERVER_ACCESS_IND_T *access_ind,
              uint16 client_config)
{
    if (access_ind->flags & ATT_ACCESS_READ)
    {
        rasHandleReadClientConfigAccess(
                    rasSrver->gattId,
                    access_ind->cid,
                    access_ind->handle,
                    client_config
                    );
    }
    else if (access_ind->flags & ATT_ACCESS_WRITE)
    {
        rasHandleWriteClientConfigAccess(
                    rasSrver,
                    access_ind
                    );
    }
    else
    {
        sendRasServerAccessErrorRsp(
                    rasSrver->gattId,
                    access_ind,
                    CSR_BT_GATT_ACCESS_RES_REQUEST_NOT_SUPPORTED
                    );
    }

}

/***************************************************************************/

void handleRasServerAccessInd(GRASS_T *rasSrver,
              const GATT_MANAGER_SERVER_ACCESS_IND_T *accessInd)
{
    uint8 index_client = rasServerGetCidIndex(rasSrver, accessInd->cid);

    if (index_client == GATT_RAS_SERVER_INVALID_CID_INDEX)
    {
        GATT_RAS_SERVER_ERROR(" \n RAS Server: handleRasServerAccessInd, "
                                              "Invalid CID Index \n");
        return;
    }

    switch (accessInd->handle)
    {
        case HANDLE_RANGING_SERVICE:
        {
            /* Service Handle read request */
            rasServerServiceAccess(rasSrver->gattId, accessInd);
            break;
        }

        case HANDLE_RAS_FEATURES:
        {
            rasServerRasFeaturesAccess(rasSrver,
                                       accessInd);
            break;
        }

        case HANDLE_REALTIME_RANGING_DATA:
        {
            /* Read/Write not supported */
            sendRasServerAccessErrorRsp(rasSrver->gattId,
                                        accessInd,
                                        CSR_BT_GATT_ACCESS_RES_REQUEST_NOT_SUPPORTED);
            break;
        }

        case HANDLE_ONDEMAND_RANGING_DATA:
        {
            /* Read/Write not supported */
            sendRasServerAccessErrorRsp(rasSrver->gattId,
                                        accessInd,
                                        CSR_BT_GATT_ACCESS_RES_REQUEST_NOT_SUPPORTED);
            break;
        }

        case HANDLE_RAS_CONTROL_POINT:
        {
            rasServerControlPointAccess(rasSrver,
                                        accessInd);
            break;
        }

        case HANDLE_RANGING_DATA_READY:
        {
            rasServerRangingDataReadyAccess(rasSrver,
                                            accessInd);
            break;
        }

        case HANDLE_RANGING_DATA_OVERWRITTEN:
        {
            rasServerRangingDataOverwrittenAccess(rasSrver,
                                                  accessInd);
            break;
        }

        case HANDLE_REALTIME_RANGING_DATA_CLIENT_CONFIG:
        {
            uint16 client_config =
                GET_RAS_CLIENT_CONFIG(rasSrver->data.connectedClients[index_client].clientCfg.realTimeDataClientCfg);

            rasHandleClientConfigAccess(rasSrver,
                                accessInd,
                                client_config);
            break;
        }

        case HANDLE_ONDEMAND_RANGING_DATA_CLIENT_CONFIG:
        {
            uint16 client_config =
                GET_RAS_CLIENT_CONFIG(rasSrver->data.connectedClients[index_client].clientCfg.onDemandDataClientCfg);

            rasHandleClientConfigAccess(rasSrver,
                                accessInd,
                                client_config);
            break;
        }

        case HANDLE_RAS_CONTROL_POINT_CLIENT_CONFIG:
        {
            uint16 client_config =
                GET_RAS_CLIENT_CONFIG(rasSrver->data.connectedClients[index_client].clientCfg.controlPointClientCfg);

            rasHandleClientConfigAccess(rasSrver,
                                accessInd,
                                client_config);
            break;
        }

        case HANDLE_RANGING_DATA_READY_CLIENT_CONFIG:
        {
            uint16 client_config =
                GET_RAS_CLIENT_CONFIG(rasSrver->data.connectedClients[index_client].clientCfg.dataReadyClientCfg);

            rasHandleClientConfigAccess(rasSrver,
                                accessInd,
                                client_config);
            break;
        }

        case HANDLE_RANGING_DATA_OVERWRITTEN_CLIENT_CONFIG:
        {
            uint16 client_config =
                GET_RAS_CLIENT_CONFIG(rasSrver->data.connectedClients[index_client].clientCfg.dataOverwrittenClientCfg);

            rasHandleClientConfigAccess(rasSrver,
                                accessInd,
                                client_config);
            break;
        }

        default:
        {
            sendRasServerAccessErrorRsp(
                        rasSrver->gattId,
                        accessInd,
                        CSR_BT_GATT_ACCESS_RES_INVALID_HANDLE
                        );
            break;
        }
    } /* switch */
}
#endif /* INSTALL_CHANNEL_SOUNDING_SUPPORT */
